<?php
/**
 * 轻舟CMS(QZLOG)
 *
 * 一款基于PHP+MYSQL的开源内容管理系统，模板标签简单、可扩展性强，利于二次开发，轻松建站的首选利器。
 *
 * @package     QZLOG
 * @license     http://www.qzlog.com/license
 * @link        http://www.qzlog.com
 * @mail        info@shyohan.com
 * @since       Version 3.0
 * @copyright   Copyright (c) 2015 - 2017 上海优翰信息科技有限公司. All rights reserved.
 */

defined('IN_QZLOG') OR exit('QZLOG:No direct script access allowed!');

/**
 * 权限控制 抽象类
 * @author LINK <link@shyohan.com>
 */
abstract class QzController extends Controller
{
    /**
     * 构造函数
     * @author LINK <link@shyohan.com>
     */
    public function __construct()
    {
        parent::__construct();
        //验证后台权限
        if (!$this->checkAdminAccess()) {
            $this->error("没有操作权限");
        }
    }

    /**
     * 后台权限验证
     * @author LINK <link@shyohan.com>
     * @return bool
     */
    protected function checkAdminAccess()
    {
        // 获取当前用户ID
        define('UID', is_login());
        if (!UID) {// 还没登录 跳转到登录页面
            go('Public/login');
        }
        // 是否是超级管理员
        define('IS_ROOT', is_administrator(UID));
        // 检测访问权限
        $access = $this->accessControl();
        if ($access === false) {
            $this->error('403:禁止访问');
        } elseif ($access === null) {
            //检测非动态权限
            $rule = strtolower('Admin/' . CONTROLLER . '/' . ACTION);
            if (!$this->checkRule($rule, array('in', '1,2'))) {
                $this->error('未授权访问!');
            } else {
                return true;
            }
        } else {
            return true;
        }
    }

    /**
     * action访问控制,在 **登陆成功** 后执行的第一项权限检测任务
     * @return boolean|null  返回值必须使用 `===` 进行判断
     * 返回 **false**, 不允许任何人访问(超管除外)
     * 返回 **true**, 允许任何管理员访问,无需执行节点权限检测
     * 返回 **null**, 需要继续执行节点权限检测决定是否允许访问
     */
    final protected function accessControl()
    {
        if (IS_ROOT) {
            return true;//管理员允许访问任何页面
        }
        $allow = C('ALLOW_VISIT');
        $deny = C('DENY_VISIT');
        $check = strtolower(CONTROLLER . '/' . ACTION);
        if (!empty($deny) && in_array_case($check, $deny)) {
            return false;//非超管禁止访问deny中的方法
        }
        if (!empty($allow) && in_array_case($check, $allow)) {
            return true;
        }
        return null;//需要检测节点权限
    }

    /**
     * 权限检测
     * @param string $rule 检测的规则
     * @param string $mode check模式
     * @return boolean
     */
    final protected function checkRule($rule, $type = 1, $mode = 'url')
    {
        if (IS_ROOT) {
            return true;//管理员允许访问任何页面
        }
        static $Auth = null;
        if (!$Auth) {
            import('Auth');
            $Auth = new Auth();
        }
        if (!$Auth->check($rule, UID, $type, $mode)) {
            return false;
        }
        return true;
    }

    /**
     * 更新后台菜单缓存
     * @author LINK <link@shyohan.com>
     * @return null
     */
    public function update_menus()
    {
        $where['hide'] = 0;
        if (!DEBUG) { // 是否开发者模式
            $where['is_dev'] = 0;
        }
        $list = M('menu')->where($where)->order('sort ASC')->all();
        foreach ($list as $key => $value) {
            if (!empty($value['group'])) {
                $list[$key]['url'] = addon_url($value['url']);
            } else {
                $list[$key]['url'] = U($value['url']);
            }
        }
        $list = Data::channelLevel($list, 0, '&nbsp;', 'id');
        //unset($list[1]);
        S('menuList', $list, 86400 * 7);
        return $list;
    }

    /**
     * 返回后台节点数据
     * @author LINK <link@shyohan.com>
     * @param bool $tree 是否返回多维数组结构(生成菜单时用到),为false返回一维数组(生成权限节点时用到)
     * @return array|mixed
     */
    final protected function returnNodes($tree = true)
    {
        static $tree_nodes = array();
        if ($tree && !empty($tree_nodes[(int)$tree])) {
            return $tree_nodes[$tree];
        }
        if ((int)$tree) {
            $list = M('menu')->order("sort ASC")->all();
            $nodes = list_to_tree($list, $pk = 'id', $pid = 'pid', $child = 'operator', $root = 0);
            foreach ($nodes as $key => $value) {
                if (!empty($value['operator'])) {
                    $nodes[$key]['children'] = $value['operator'];
                    unset($nodes[$key]['operator']);
                }
            }
        } else {
            $nodes = M('menu')->order("sort ASC")->all();
        }
        $tree_nodes[(int)$tree] = $nodes;
        return $nodes;
    }
}












